/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.dotexe.webframework.core.datasources;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import javax.swing.event.EventListenerList;

import org.json.JSONException;
import org.json.JSONObject;

import com.dotexe.webframework.core.bindings.BindingCollectionSource;
import com.dotexe.webframework.core.collectionsource.SourceField;
import com.dotexe.webframework.core.collectionsource.SourceRow;
import com.dotexe.webframework.core.eventargs.DataUpdate;
import com.dotexe.webframework.core.eventargs.RefreshStateArgs;

/**
 *
 * @author jovan.tomasevic
 */
public class CollectionDataSource extends DataSource {

    private String idFiled;
    private Object selectedItem;
    private ArrayList<Object> selectedItems;
    private boolean multiselect;
    protected EventListenerList listenerList = new EventListenerList();

    public void addSelectedIndexChangedListener(SelectedIndexChangeEventListener listener) {
        listenerList.add(SelectedIndexChangeEventListener.class, listener);
    }

    public void removeSelectedIndexChangedListener(SelectedIndexChangeEventListener listener) {
        listenerList.add(SelectedIndexChangeEventListener.class, listener);
    }

    public CollectionDataSource() {
        this("");
        //this.selectedItems = new ArrayList<Object>();
    }

    public CollectionDataSource(String name) {
        super(name);
        this.selectedItems = new ArrayList<Object>();

    }

    public CollectionDataSource(String name, boolean multiSelect) {
        super(name);
        this.selectedItems = new ArrayList<Object>();
        this.multiselect = multiSelect;

    }

    @Override
    public void setSource(Object value) {
        this.selectedItem = null;
        this.selectedItems = new ArrayList<Object>();
        this.Source = value;
    }

    public void update(RefreshStateArgs args, DataUpdate get)
            throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, JSONException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
        if (args.selectedItemId != null) {
            Object obj = this.get((int) (long) args.selectedItemId);
            this.selectedItem = obj;
            if (args.selectedItemId == -1 && this.selectedItem != null) {
            }
        }

        if (this.isMultiselect()) {
            this.selectedItems = new ArrayList<Object>();
            if (args.selectedItemIds != null) {
                for (int i = 0; i < args.selectedItemIds.length; i++) {
                    int index = (int) args.selectedItemIds[i];
                    Object s = ((ArrayList) this.Source).get(index);
                    this.selectedItems.add(s);
                }
            }
            //this.selectedItems = new ArrayList<Object>();
//            args.selectedItemIds = new long[this.selectedItems.size()];
//            for (int i = 0; i < args.selectedItemIds.length; i++) {
//                Object o = this.get((int) args.selectedItemIds[i]);
//                this.selectedItems.add(o);
//            }
        }
        for (SelectedIndexChangeEventListener lis : listenerList.getListeners(SelectedIndexChangeEventListener.class)) {
            SelectedIndexChangeEvent e = new SelectedIndexChangeEvent(this);
            e.setSelectedItem(this.selectedItem);
            e.setSelectedItems(this.selectedItems);
            lis.SelectedIndexChangeEventOccurred(e);
        }
    }

    public Object get(int index) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        if (this.Source == null) {
            // throw exception
            return null;
        } else {
            Class cls = this.Source.getClass();
            Method get = cls.getMethod("get", int.class);
            Object obj = get.invoke(this.Source, index);
            return obj;
        }
    }

    public int size() throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class cls = this.Source.getClass();
        Method sizeMethod = cls.getMethod("size");
        Integer size = (Integer) sizeMethod.invoke(this.Source);
        return size;
    }

    public Object getByIdFiled(Object fieldValue) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
        for (int i = 0; i < this.size(); i++) {
            Object obj = this.get(i);
            Object v = obj.getClass().getDeclaredField(this.idFiled).get(obj);
            if (v.toString().equals(fieldValue.toString())) {
                return obj;
            }
        }
        return null;
    }

    public void bind(ArrayList<String> propertiesToBind)
            throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, JSONException, SecurityException, NoSuchMethodException, InvocationTargetException {
        BindingCollectionSource binding = new BindingCollectionSource();
        binding.setName(this.getName());
        Integer size = size();
        if (size > 0) {
            SourceField ruid = new SourceField();
            ruid.setName("ruid");
            ruid.setType("auto");
            binding.getSource().getFields().put(ruid);
            for (int i = 0; i < propertiesToBind.size(); i++) {
                SourceField field = new SourceField();
                field.setName(propertiesToBind.get(i));
                field.setType("auto");
                binding.getSource().getFields().put(field);
            }
        }
        for (int i = 0; i < size; i++) {
            // get object from collection with index i
            Object obj = this.get(i);
            SourceRow row = new SourceRow();

            row.put(i);
            for (int j = 0; j < propertiesToBind.size(); j++) {
                Method m = obj.getClass().getMethod(String.format("get%s", propertiesToBind.get(j)));
                Object fValue = m.invoke(obj);
                if (fValue == null) {
                    fValue = JSONObject.NULL;
                }
                row.put(fValue);
            }
            binding.getSource().getRows().put(row);
            if (this.selectedItem != null && this.selectedItem == obj) {
                binding.setSelectedValue(i);

            }
        }

          List list = (List) this.Source;
            if (this.selectedItems != null) {
                ArrayList<Integer> itemsIndexes = new ArrayList<Integer>();
                for (Object item : selectedItems) {
                    int index = list.indexOf(item);
                    itemsIndexes.add(index);
                }
                
                binding.setSelectedValues(itemsIndexes);
            }

        this.BindingSource = binding;
    }

    public void bind()
            throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, JSONException, NoSuchMethodException, InvocationTargetException {
        ArrayList<String> propertiesToBind = new ArrayList<String>();
        Integer size = size();
        if (size > 0) {
            Object obj = this.get(0);
            Field[] fields = obj.getClass().getDeclaredFields();
            for (int j = 0; j < fields.length; j++) {
                Field f = fields[j];
                propertiesToBind.add(f.getName());
            }
        }
        this.bind(propertiesToBind);
    }

    /**
     * @return the selectedItem
     */
    public Object getSelectedItem() {
        return selectedItem;
    }

    /**
     * @param selectedItem the selectedItem to set
     */
    public void setSelectedItem(Object selectedItem) {
        this.selectedItem = selectedItem;
    }

    /**
     * @return the selectedItems
     */
    public ArrayList<Object> getSelectedItems() {
        return selectedItems;
    }

    /**
     * @param selectedItems the selectedItems to set
     */
    public void setSelectedItems(ArrayList<Object> selectedItems) {
        this.selectedItems = selectedItems;
    }

    /**
     * @return the idFiled
     */
    public String getIdFiled() {
        return idFiled;
    }

    /**
     * @param idFiled the idFiled to set
     */
    public void setIdFiled(String idFiled) {
        this.idFiled = idFiled;
    }

    /**
     * @return the multiselect
     */
    public boolean isMultiselect() {
        return multiselect;
    }

    /**
     * @param multiselect the multiselect to set
     */
    public void setMultiselect(boolean multiselect) {
        this.multiselect = multiselect;
    }
}
